<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-04-09
 * Time: 15:13
 */

namespace app\admin\model;


use app\admin\model\traits\NavTree;
use app\common\exception\LoginException;
use app\common\exception\ParameterException;
use app\common\exception\SuperAdminException;
use app\common\exception\UserException;
use app\common\model\BaseModel;
use app\common\service\JWTToken;
use app\common\validate\IDMustBeRequire;
use think\model\concern\SoftDelete;
use app\admin\validate\Admin as Validate;
use app\admin\model\AuthRoleUser as AuthRoleUserModel;

class Admin extends BaseModel
{
    protected const CURRENT_KEY = 'admin_current_user';

    protected $hidden = ['update_time', 'delete_time'];

    // 使用软删除
    use SoftDelete;
    protected $deleteTime = 'delete_time';

    use NavTree;

    public function authRole()
    {
        return $this->belongsTo('AuthRole','role_id','id')
            ->field(['id','title','name']);
    }

    public function menus()
    {
        // belongsToMany('关联模型','中间表','外键','关联键');
        // 关联模型（必须）：关联模型类名
        // 中间表：默认规则是当前模型名+_+关联模型名 （可以指定模型名）
        // 外键：中间表的当前模型外键，默认的外键名规则是关联模型名+_id
        // 关联键：中间表的当前模型关联键名，默认规则是当前模型名+_id
        return $this->belongsToMany('AuthMenu','\\app\\admin\\model\\AuthRoleMenu','menu_id','role_id');
    }

    /**
     * 保存密码时进行加密
     * @param string $value
     * @return bool|string
     */
    public function setPasswordAttr(string $value)
    {
        if (!empty($value)) {
            return password_hash($value, PASSWORD_DEFAULT);
        } else {
            return $value;
        }
    }

    /**
     * 去除简介中的xss代码
     * @param string $value
     * @return string
     */
    public function setIntroductionAttr(string $value)
    {
        return remove_xss($value);
    }

    /**
     * 为图片添加域名前缀
     * @param $value
     * @param $data
     * @return array
     */
    public function getAvatarAttr($value, $data)
    {
        return [
            'value' => $value,
            'prefix' => $this->prefixImgUrl($value)
        ];
    }

    public static function onBeforeUpdate(Admin $admin)
    {
        // 查找出数据库的旧数据
        $oldData = self::find($admin->id);

        static::delDifferentImage($oldData, $admin, 'avatar');

        return true;
    }

    /**
     * 管理员登陆
     * @param array $data
     * @return \Lcobucci\JWT\Token
     */
    public static function login(array $data)
    {
        $validate = new Validate();
        if (!$validate->scene('login')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError()
            ]);
        }

        $admin = static::where([['user_name','=',$data['user_name']],['status','=',1]])
            ->find();

        if (empty($admin) || !password_verify($data['password'], $admin->password)) {
            write_system_log('登陆失败', $data['user_name']);
            throw new LoginException();
        }

        write_system_log('登陆成功', $data['user_name']);

        // 生成jwt token
        return (new JWTToken())->generateJWTToken([
            'uid' => $admin->id,
            'user_name' => $admin->user_name
        ]);
    }

    /**
     * 获取当前登陆管理员的用户的信息
     * @return mixed
     */
    public static function getCurrentUser()
    {
        // 验证token是否有效，并获取对应的信息
        return (new JWTToken())->verifyJWTToken();
    }

    /**
     * 退出当前登陆的管理员，并清除相关信息
     */
    public static function logout($uid)
    {
        // 判断当前退出的用户是否存在
        $admin = static::where([['id','=',$uid],['status','=',1]])
            ->find();
        if (empty($admin)) {
            throw new UserException();
        }
    }

    /**
     * 获取对应管理员的菜单路由信息
     * @param array $data
     * @return array
     */
    public static function getRoutes(array $data)
    {
        // 根据id获取对应的菜单信息
//        $admin_data = static::with(['menus' => function($query) {
//            $query->order('sort','asc');
//        }])->find($data['uid']);
        $admin_data = static::with(['authRole' => function($query) {
            $query->with(['menus' => function($query) {
                $query->order('sort','asc');
            }]);
        }])->find($data['uid'])
            ->hidden(['password']);
        if (empty($admin_data)) {
            throw new UserException();
        }

        $menu_data = $admin_data
            ->authRole
            ->menus
            ->toArray();

        return [
            'routes' => self::buildElementNavMenu($menu_data)
        ];
    }

    /**
     * 获取用户相关信息
     * @param array $data
     * @return array
     */
    public static function getInfo(array $data)
    {
        $admin = static::where([['id','=',$data['uid']],['status','=',1]])
            ->with(['authRole'])
            ->find();
        if (empty($admin)) {
            throw new UserException();
        } else {
            return [
                'name' => $admin->nick_name,
                'introduction' => $admin->introduction,
                'avatar' => $admin->avatar['prefix'],
                'roles' => [$admin->authRole['name']]
            ];
        }
    }

    /**
     * 获取管理员的分页数据
     * @param array $params
     * @return \think\Paginator
     */
    public static function getPaginationList($token_data,array $params)
    {
        static::validatePaginationData($params);

        $static = new static();

        if ($token_data['uid'] != 1) {
            $static = $static->where([['id','=',$token_data['uid']]]);
        }

        $static = $static->with(['authRole']);

        $static = $static->hidden(['password']);

        foreach ($params as $name => $value) {
            $value = trim($value);
            switch ($name) {
                case 'user_name':
                    if (!empty($value)) {
                        $like_text = '%' . $value . '%';
                        $static = $static->whereLike('user_name', $like_text);
                    }
                    break;
                case 'nick_name':
                    if (!empty($value)) {
                        $like_text = '%' . $value . '%';
                        $static = $static->whereLike('nick_name', $like_text);
                    }
                    break;
                case 'role_id':
                    if (!empty($value)) {
                        $static = $static->where('role_id','=',intval($value));
                    }
                    break;
            }
        }

        return $static
            ->paginate([
                'page' => $params['page'],
                'list_rows' => $params['limit']
            ], false);
    }

    /**
     * 根据id获取管理员信息
     * @param $id
     * @return array|\think\Model|null
     */
    public static function getAdminByID($id)
    {
        $validate = new IDMustBeRequire();
        if (!$validate->check(['id'=>$id])) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        $result = static::field(['id','user_name','nick_name','gender','avatar','introduction','role_id','status'])
            ->find($id);

        if (!$result) {
            return [];
        } else {
            return $result;
        }
    }

    /**
     * 添加管理员
     * @param array $data
     * @return bool
     */
    public static function addAdmin(array $data)
    {
        $validate = new Validate();
        if (!$validate->scene('add')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError()
            ]);
        }

        $static = new static();
        $static->startTrans();
        try {
            $static->allowField(['user_name','nick_name','password','avatar','gender','introduction','role_id','status'])
                ->save($data);
            $static = $static->refresh();

            // 更新用户与权限组之间的关系
            AuthRoleUserModel::create([
                'user_id' => $static->id,
                'role_id' => $data['role_id']
            ]);

            $static->commit();

        } catch (\Exception $e) {
            $static->rollback();
            return false;
        }

        return true;
    }

    /**
     * 编辑管理员
     * @param array $data
     * @return bool
     */
    public static function editAdmin(array $data)
    {
        $validate = new Validate();
        // 判断是否有修改密码
        if (isset($data['password']) && !empty($data['password'])) {
            if (!$validate->scene('edit')->check($data)) {
                throw new ParameterException([
                    'msg' => $validate->getError()
                ]);
            }
        } else {
            if (!$validate->scene('edit_no_password')->check($data)) {
                throw new ParameterException([
                    'msg' => $validate->getError()
                ]);
            }

            // 从data数组中去除password字段，防止被覆盖
            unset($data['password']);
        }

        // 防止溢权操作，可以修改自己所在的用户组
        // 只有超级管理员才可以修改对应用户的用户组信息
        $currentUser = $data['token_data'];
        if ($currentUser['uid'] !== 1 && $data['id'] === 1) {
            throw new SuperAdminException();
        }
        if ($currentUser['uid'] !== 1) {
            // 从提交的数据中去除role_id字段数据
            unset($data['role_id']);
        }

        $static = static::find($data['id']);
        $static->startTrans();
        try {
            $oldRoleID = $static->role_id;
            $static->allowField(['user_name','nick_name','password','avatar','gender','introduction','role_id','status'])
                ->save($data);
            $static = $static->refresh();

            // 更新用户与权限组之间的关系
            // 更新用户与权限组关系表的数据
            if ($currentUser['uid'] === 1 && $oldRoleID != $data['role_id']) {
                AuthRoleUserModel::where('user_id','=',$static->id)->delete();
                AuthRoleUserModel::create([
                    'user_id'=>$static->id,
                    'role_id'=>$data['role_id'],
                ]);
            }

            $static->commit();

        } catch (\Exception $e) {
            $static->rollback();
            return false;
        }

        return true;
    }
}